/**
 * @file mc907.c
 * @brief NBIoT模块
 *
 * @author 刘伟
 *
 * @date 2022-05-09
 *
 * @copyright 海南大学 - 追光者
 */
#ifdef APP_USING_NBIOT

#include <rtthread.h>
#include <rtdevice.h>
#include "drv_common.h"
#include "app_main.h"
#include <at.h>

#define DBG_TAG "mc907       "
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

rt_device_t dev_nbiot;
static at_response_t resp;
static uint8_t publish_buff[512];

/**
 * 网络连接成功回调
 */
static void net_connected_cb(at_client_t at_client, const char *data, rt_size_t size)
{
    LOG_I("net ready.");
    rt_event_send(s_event, EVENT_NBIOT_NET_READY);
}

/**
 * MQTT连接成功回调
 */
static void mqtt_connected_cb(at_client_t at_client, const char *data, rt_size_t size)
{
    LOG_I("mqtt ready.");
    rt_event_send(s_event, EVENT_NBIOT_MQTT_READY);
}

/**
 * 发布消息回调
 */
static void mqtt_puback_db(at_client_t at_client, const char *data, rt_size_t size)
{
    LOG_D("mqtt_puback: %s", data);
    int result = -1;
    sscanf(data, "+MQTTPUBACK: %d,%d,%d", &result, &result, &result);
    if (result == 0)
    {
        LOG_I("mqtt publish success.");
        rt_event_send(s_event, EVENT_NBIOT_PUBLISHED);
    }
}

/**
 * 联网线程
 */
void nbiot_connect_thread(void *params)
{
    /* 判断是否已联网 */
    int ret;

    while (1)
    {
        int e = 0;

        rt_event_recv(s_event, EVENT_NBIOT_NET_READY, RT_EVENT_FLAG_OR, 0, &e);
        if (e)
            break;

        resp = at_resp_set_info(resp, 512, 4, rt_tick_from_millisecond(5000));
        ret = at_exec_cmd(resp, "AT+CEREG?");
        LOG_D("response ret: %d, line_counts: %d", ret, resp->line_counts);

        rt_thread_mdelay(3000);
    };

    while (1)
    {
        rt_uint32_t e = 0;

        rt_event_recv(s_event, EVENT_NBIOT_MQTT_READY, RT_EVENT_FLAG_OR, 0, &e);
        if (!e)
        {
            resp = at_resp_set_info(resp, 512, 4, rt_tick_from_millisecond(3000));
            ret = at_exec_cmd(resp, "AT+MQTTCONN?");
            LOG_D("response ret: %d, line_counts: %d", ret, resp->line_counts);
            rt_event_recv(s_event, EVENT_NBIOT_MQTT_READY, RT_EVENT_FLAG_OR, 0, &e);
            if (!e)
            {
                if (at_resp_parse_line_args(resp, 2, "+MQTTCONN=%d,", &ret) == 1 && ret == 3)
                {
                    mqtt_connected_cb((at_client_t) 0, (const char *) 0, 0);
                }
                else
                {
                    resp = at_resp_set_info(resp, 512, 2, rt_tick_from_millisecond(1000));
                    ret = at_exec_cmd(resp, "AT+MQTTCFG=\"host\",0,"APP_MQTT_HOSTNAME","APP_MQTT_PORT);
                    LOG_D("response ret: %d, line_counts: %d", ret, resp->line_counts);
                    ret = at_exec_cmd(resp, "AT+MQTTCFG=\"clientid\",0,"APP_MQTT_CLIENTID);
                    LOG_D("response ret: %d, line_counts: %d", ret, resp->line_counts);
                    resp = at_resp_set_info(resp, 512, 2, rt_tick_from_millisecond(5000));
                    ret = at_exec_cmd(resp, "AT+MQTTCONN=0,0,0,"APP_MQTT_USERNAME","APP_MQTT_PASSWROD);
                    LOG_D("response ret: %d, line_counts: %d", ret, resp->line_counts);
                }
            }
            else
            {
                LOG_I("connected");
                break;
            }

        }

        rt_thread_mdelay(1000);
        // TODO: 检测网络断开，重连
    }
}

/**
 * 发布mqtt消息，如果MQTT未连接将阻塞等到MQTT连接成功
 * @param msg 消息指针
 * @return 0代表成功否则失败
 */
int nbiot_mqtt_publish(uint8_t *msg)
{
    /* 等待MQTT连接成功 */
    rt_event_recv(s_event, EVENT_NBIOT_MQTT_READY, RT_EVENT_FLAG_OR, RT_WAITING_FOREVER, NULL);

    /* MC907 MQTT发布不支持逗号 */
    for (int i = 0; i < strlen(msg); ++i)
    {
        if (msg[i] == ',')
        {
            msg[i] = '\'';
        }
    }

    sprintf(publish_buff, "AT+MQTTPUB=0,1,0,0,%s,%s", APP_MQTT_PUBLISH_TOPIC, msg);

    resp = at_resp_set_info(resp, 512, 2, rt_tick_from_millisecond(3000));
    rt_event_recv(s_event, EVENT_NBIOT_PUBLISHED, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0, NULL);
    at_exec_cmd(resp, publish_buff);

    if (rt_event_recv(s_event, EVENT_NBIOT_PUBLISHED, RT_EVENT_FLAG_OR, 1000, NULL) == 0)
        return 0;

    return -1;
}

/**
 * 通过命令行调试模块
 * @param argc 参数个数
 * @param argv 参数值数组
 *
 * @code
 * test_nbiot_cmd AT\n
 * @endcode
 */
static void test_nbiot_cmd(int argc, char**argv)
{
    if (argc == 2)
    {
        resp = at_resp_set_info(resp, 512, 3, rt_tick_from_millisecond(3000));
        at_exec_cmd(resp, argv[1]);
    }

}
MSH_CMD_EXPORT(test_nbiot_cmd, send cmd to nbiot);

/**
 * URC上报处理表
 */
struct at_urc urc_table[] = { //
        { "+MQTTCONN=3,1,1", "\r\n", mqtt_connected_cb }, //
                { "+MQTTCONNACK: 0,0,0", "\r\n", mqtt_connected_cb }, //
                { "+CEREG:0,1", "\r\n", net_connected_cb }, //
                { "+MQTTPUBACK: ", "\r\n", mqtt_puback_db }, { "ERROR: 0,89", "\r\n", mqtt_puback_db }, };

#ifdef APP_USING_NBIOT
int nbiot_init()
{
    dev_nbiot = rt_device_find(NBIOT_DEV_NAME);
    rt_device_open(dev_nbiot, RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX);

    at_client_init(NBIOT_DEV_NAME, 512);

    /* 添加多种 URC 数据至 URC 列表中，当接收到同时匹配 URC 前缀和后缀的数据，执行 URC 函数  */
    at_set_urc_table(urc_table, sizeof(urc_table) / sizeof(urc_table[0]));
    /* 创建响应结构体，设置最大支持响应数据长度为 512 字节，响应数据行数无限制，超时时间 */
    resp = at_create_resp(512, 0, rt_tick_from_millisecond(300));

    rt_thread_t thread = rt_thread_create("nbiot", nbiot_connect_thread, NULL, 2048, PRIO_NBIOT, 10);
    rt_thread_startup(thread);

    return 0;
}
INIT_APP_EXPORT(nbiot_init);
#endif /* APP_USING_NBIOT */

#endif /* APP_USING_NBIOT */
